1   /*
2    * Written by Doug Lea and Martin Buchholz with assistance from
3    * members of JCP JSR-166 Expert Group and released to the public
4    * domain, as explained at
5    * http://creativecommons.org/publicdomain/zero/1.0/
6    */
7   
8   /*
9    * Source:
10   * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/extra/AtomicDouble.java?revision=1.13
11   * (Modified to adapt to guava coding conventions and
12   * to use AtomicLongFieldUpdater instead of sun.misc.Unsafe)
13   */
14  
15  package com.google.common.util.concurrent;
16  
17  import static java.lang.Double.doubleToRawLongBits;
18  import static java.lang.Double.longBitsToDouble;
19  
20  import java.util.concurrent.atomic.AtomicLongFieldUpdater;
21  
22  /**
23   * A {@code double} value that may be updated atomically.  See the
24   * {@link java.util.concurrent.atomic} package specification for
25   * description of the properties of atomic variables.  An {@code
26   * AtomicDouble} is used in applications such as atomic accumulation,
27   * and cannot be used as a replacement for a {@link Double}.  However,
28   * this class does extend {@code Number} to allow uniform access by
29   * tools and utilities that deal with numerically-based classes.
30   *
31   * <p><a name="bitEquals">This class compares primitive {@code double}
32   * values in methods such as {@link #compareAndSet} by comparing their
33   * bitwise representation using {@link Double#doubleToRawLongBits},
34   * which differs from both the primitive double {@code ==} operator
35   * and from {@link Double#equals}, as if implemented by:
36   *  <pre> {@code
37   * static boolean bitEquals(double x, double y) {
38   *   long xBits = Double.doubleToRawLongBits(x);
39   *   long yBits = Double.doubleToRawLongBits(y);
40   *   return xBits == yBits;
41   * }}</pre>
42   *
43   * <p>It is possible to write a more scalable updater, at the cost of
44   * giving up strict atomicity.  See for example
45   * <a href="http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166edocs/jsr166e/DoubleAdder.html">
46   * DoubleAdder</a>
47   * and
48   * <a href="http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166edocs/jsr166e/DoubleMaxUpdater.html">
49   * DoubleMaxUpdater</a>.
50   *
51   * @author Doug Lea
52   * @author Martin Buchholz
53   * @since 11.0
54   */
55  public class AtomicDouble extends Number implements java.io.Serializable {
56    private static final long serialVersionUID = 0L;
57  
58    private transient volatile long value;
59  
60    private static final AtomicLongFieldUpdater<AtomicDouble> updater =
61        AtomicLongFieldUpdater.newUpdater(AtomicDouble.class, "value");
62  
63    /**
64     * Creates a new {@code AtomicDouble} with the given initial value.
65     *
66     * @param initialValue the initial value
67     */
68    public AtomicDouble(double initialValue) {
69      value = doubleToRawLongBits(initialValue);
70    }
71  
72    /**
73     * Creates a new {@code AtomicDouble} with initial value {@code 0.0}.
74     */
75    public AtomicDouble() {
76      // assert doubleToRawLongBits(0.0) == 0L;
77    }
78  
79    /**
80     * Gets the current value.
81     *
82     * @return the current value
83     */
84    public final double get() {
85      return longBitsToDouble(value);
86    }
87  
88    /**
89     * Sets to the given value.
90     *
91     * @param newValue the new value
92     */
93    public final void set(double newValue) {
94      long next = doubleToRawLongBits(newValue);
95      value = next;
96    }
97  
98    /**
99     * Eventually sets to the given value.
100    *
101    * @param newValue the new value
102    */
103   public final void lazySet(double newValue) {
104     set(newValue);
105     // TODO(user): replace with code below when jdk5 support is dropped.
106     // long next = doubleToRawLongBits(newValue);
107     // updater.lazySet(this, next);
108   }
109 
110   /**
111    * Atomically sets to the given value and returns the old value.
112    *
113    * @param newValue the new value
114    * @return the previous value
115    */
116   public final double getAndSet(double newValue) {
117     long next = doubleToRawLongBits(newValue);
118     return longBitsToDouble(updater.getAndSet(this, next));
119   }
120 
121   /**
122    * Atomically sets the value to the given updated value
123    * if the current value is <a href="#bitEquals">bitwise equal</a>
124    * to the expected value.
125    *
126    * @param expect the expected value
127    * @param update the new value
128    * @return {@code true} if successful. False return indicates that
129    * the actual value was not bitwise equal to the expected value.
130    */
131   public final boolean compareAndSet(double expect, double update) {
132     return updater.compareAndSet(this,
133                                  doubleToRawLongBits(expect),
134                                  doubleToRawLongBits(update));
135   }
136 
137   /**
138    * Atomically sets the value to the given updated value
139    * if the current value is <a href="#bitEquals">bitwise equal</a>
140    * to the expected value.
141    *
142    * <p>May <a
143    * href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html#Spurious">
144    * fail spuriously</a>
145    * and does not provide ordering guarantees, so is only rarely an
146    * appropriate alternative to {@code compareAndSet}.
147    *
148    * @param expect the expected value
149    * @param update the new value
150    * @return {@code true} if successful
151    */
152   public final boolean weakCompareAndSet(double expect, double update) {
153     return updater.weakCompareAndSet(this,
154                                      doubleToRawLongBits(expect),
155                                      doubleToRawLongBits(update));
156   }
157 
158   /**
159    * Atomically adds the given value to the current value.
160    *
161    * @param delta the value to add
162    * @return the previous value
163    */
164   public final double getAndAdd(double delta) {
165     while (true) {
166       long current = value;
167       double currentVal = longBitsToDouble(current);
168       double nextVal = currentVal + delta;
169       long next = doubleToRawLongBits(nextVal);
170       if (updater.compareAndSet(this, current, next)) {
171         return currentVal;
172       }
173     }
174   }
175 
176   /**
177    * Atomically adds the given value to the current value.
178    *
179    * @param delta the value to add
180    * @return the updated value
181    */
182   public final double addAndGet(double delta) {
183     while (true) {
184       long current = value;
185       double currentVal = longBitsToDouble(current);
186       double nextVal = currentVal + delta;
187       long next = doubleToRawLongBits(nextVal);
188       if (updater.compareAndSet(this, current, next)) {
189         return nextVal;
190       }
191     }
192   }
193 
194   /**
195    * Returns the String representation of the current value.
196    * @return the String representation of the current value
197    */
198   public String toString() {
199     return Double.toString(get());
200   }
201 
202   /**
203    * Returns the value of this {@code AtomicDouble} as an {@code int}
204    * after a narrowing primitive conversion.
205    */
206   public int intValue() {
207     return (int) get();
208   }
209 
210   /**
211    * Returns the value of this {@code AtomicDouble} as a {@code long}
212    * after a narrowing primitive conversion.
213    */
214   public long longValue() {
215     return (long) get();
216   }
217 
218   /**
219    * Returns the value of this {@code AtomicDouble} as a {@code float}
220    * after a narrowing primitive conversion.
221    */
222   public float floatValue() {
223     return (float) get();
224   }
225 
226   /**
227    * Returns the value of this {@code AtomicDouble} as a {@code double}.
228    */
229   public double doubleValue() {
230     return get();
231   }
232 
233   /**
234    * Saves the state to a stream (that is, serializes it).
235    *
236    * @serialData The current value is emitted (a {@code double}).
237    */
238   private void writeObject(java.io.ObjectOutputStream s)
239       throws java.io.IOException {
240     s.defaultWriteObject();
241 
242     s.writeDouble(get());
243   }
244 
245   /**
246    * Reconstitutes the instance from a stream (that is, deserializes it).
247    */
248   private void readObject(java.io.ObjectInputStream s)
249       throws java.io.IOException, ClassNotFoundException {
250     s.defaultReadObject();
251 
252     set(s.readDouble());
253   }
254 }